#include "clientMessage.h"
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include "clientInfo.h"
#include <stdio.h>
void (*getRoomsFunc)(void);
void (*getUsersFunc)(void);
void (*getChatFunc)(char*);
static int server_fd;
static struct message resultMsg;//메세지 값을 저장하는 저장소.
static pthread_mutex_t mutex_send;
static sem_t sem_message[10], sem_msgBuf;
int sendMessage(int sendFd, struct message msg);
void getChat(char* chat);
void updateUser(struct userInfo *list, int cnt);
void updateRoom(struct roomInfo *list, int cnt);
void init_clientMessage(int fd){
	server_fd=fd;
	pthread_mutex_init(&mutex_send, NULL);
	int i;
	for(i=0;i<10;i++){
		sem_init(&sem_message[i],0,0);
	}
	sem_init(&sem_msgBuf,0,1);
}
//유저가 서버에 접속(리턴값 : 유저 id)
int enterUser(const char* name){
	struct message msg;
	msg.type=0x20;
	msg.roomNo=0;
	strcpy((char*)msg.msg,name);
	msg.length=(unsigned int)(4+strlen(name)+1);

	sendMessage(server_fd,msg);
	sem_wait(&sem_message[0]);
	memmove((void*)&myUserInfo,(void*)&resultMsg.msg,sizeof(struct userInfo));
	sem_post(&sem_msgBuf);
	myRoomInfo.roomID=0;
	strcpy(myRoomInfo.name,"로비");
	return myUserInfo.userID;
}
//유저가 서버에서 나감
int quitUser(void){
	struct message msg;
	msg.length=3;
	msg.type=0x00;
	sendMessage(server_fd,msg);
	return 1;
}
//유저가 방에 입장(리턴값 : 입장한 방의 id)
int joinRoom(unsigned int id){
	struct message msg;
	msg.length=4;
	msg.type=0x21;
	msg.roomNo=id;
	sendMessage(server_fd,msg);
	sem_wait(&sem_message[1]);
	memmove((void*)&myRoomInfo,(void*)&resultMsg.msg,sizeof(struct roomInfo));
	sem_post(&sem_msgBuf);
	return myRoomInfo.roomID;
}
//유저가 방을 생성(리턴값 : 생성한 방의 id)
int makeRoom(const char* name){
	struct message msg;
	msg.type=0x22;
	msg.roomNo=0;
	strcpy((char*)msg.msg,name);
	msg.length=4+strlen(name)+1;
	sendMessage(server_fd,msg);
	sem_wait(&sem_message[2]);
	memmove((void*)&myRoomInfo,(void*)&resultMsg.msg,sizeof(struct roomInfo));
	sem_post(&sem_msgBuf);
	return myRoomInfo.roomID;
}
//유저가 채팅함
int sendChat(const char* chat, unsigned int roomID){
	struct message msg;
	msg.type=0x01;
	msg.roomNo=roomID;
	size_t len=strlen(chat);
	if(len>=MESSAGE_SIZE-4){
	   	len=MESSAGE_SIZE-5;
		memmove(msg.msg,chat,MESSAGE_SIZE-5);	
		msg.msg[MESSAGE_SIZE-4]='\0';
	}
	else{
		memmove(msg.msg,chat,len+1);
	}
	msg.length=4+len+1;
	printf("send Chat, bytes : %d\n",len);
	return sendMessage(server_fd,msg);
}

int sendMessage(int sendFd, struct message msg){
	size_t len=msg.length;
	void* buf=(void*)&msg;
	char *bufp;
   	size_t bytestowrite;
   	ssize_t byteswritten;
   	size_t totalbytes;
	int result=0;
	//두개 이상의 값이 write되지 않도록 잠금.
	pthread_mutex_lock(&mutex_send);
   	
	for (bufp = buf, bytestowrite = len, totalbytes = 0;
       		bytestowrite > 0;
        	bufp += byteswritten, bytestowrite -= byteswritten) {
      	
		byteswritten = write(sendFd, bufp, bytestowrite);
      	if ((byteswritten == -1) && (errno != EINTR)){
			totalbytes=-1;
         	break;
		}
      	if (byteswritten == -1)
         	byteswritten = 0;
      	totalbytes += byteswritten;
  	}
	pthread_mutex_unlock(&mutex_send);	
	return totalbytes;
}
int receiveMessage(struct message msg){

	printf("type : %x\n",msg.type);

	//메세지 타입이 0x3?이면 
	if((msg.type&0xF0)==0x30){
		//메세지 버퍼 잠금
		sem_wait(&sem_msgBuf);
		resultMsg=msg;
		//요청에 해당하는 함수의 lock 해제.
		sem_post(&sem_message[msg.type&0x0F]);
	}
	else if((msg.type&0xF0)==0x10){
		if(msg.type==0x11)//채팅 받아오기
		{
			getChat((char*)msg.msg);
		}
		if(msg.type==0x10)//방 폭파
		{
			myRoomInfo.roomID=0;
			strcpy(myRoomInfo.name,"로비");
			printf("방장이 나가서 로비로 갔습니다.\n");	
		}
		//방 리스트 업데이트 
		if(msg.type==0x12){
			printf("roomUpdate\n");
			int len=msg.length;
			int cnt=(len-4)/sizeof(struct roomInfo);
			struct roomInfo list[10];
			memmove((void*)list,(void*)msg.msg,msg.length-4);
			updateRoom(list,cnt);

		}
		//유저 리스트 업데이트
		if(msg.type==0x13){
			printf("userUpdate\n");
			int len=msg.length;
			int cnt=(len-4)/sizeof(struct userInfo);
			struct userInfo list[10];
			memmove((void*)list,(void*)msg.msg,msg.length-4);
			updateUser(list,cnt);
		}
	}
}


void* receiver(void *arg){
	int fd=(int)arg;
	struct message receiveMsg;
	unsigned char buf[MESSAGE_SIZE];
	while(1){
		int numbytes=0;
		while((numbytes=recv(fd,(void*)&receiveMsg,MESSAGE_SIZE,0))<0
				&& errno==EWOULDBLOCK);
		if(numbytes<=0)//서버 닫힘.
			break;
		receiveMessage(receiveMsg);
	}
	pthread_exit(NULL);
}

void getChat(char* chat){
	printf("%s\n",chat);
	if(getChatFunc!=NULL)
		getChatFunc(chat);
}
void updateUser(struct userInfo* list, int cnt){
	int i;
	usersNum=cnt;
	for(i=0;i<cnt;i++){
		printf("사람번호 : %d 사람이름 : %s\n",
				list[i].userID, list[i].name);
		usersList[i]=list[i];
	}
	if(getUsersFunc!=NULL)
		getUsersFunc();
}
void updateRoom(struct roomInfo* list, int cnt){
	int i;
	roomsNum=cnt;
	for(i=0;i<cnt;i++){
		printf("방번호 : %d, 방이름 : %s\n",
				list[i].roomID,list[i].name);
		roomsList[i]=list[i];
	}
	if(getRoomsFunc!=NULL){
		getRoomsFunc();
	}
}
